import Axios, { type AxiosRequestConfig, type AxiosInstance } from 'axios'
import type {
  KptHttpRequestConfig,
  RequestMethods,
  KptHttpResponse,
  KptHttpError,
} from './types'
import { formatToken, getToken } from '@/util/auth'

const defaultConfig: AxiosRequestConfig = {
  timeout: 5000,
  headers: {
    Accept: 'application/json, text/plan,*/*',
    'Content-Type': 'application/json',
    'X-Requested-With': 'XMLHttpRequest',
  },
}

class KptHttp {
  constructor() {
    this.httpInterceptorsRequest()
    this.httpInterceptorsResponse()
  }

  /** token过期后，暂存待执行的请求 */
  private static requests = []

  /** 防止重复刷新token */
  private static isRefreshing = false

  /** 初始化配置对象 */
  private static initConfig: KptHttpRequestConfig = {}

  private static axiosInstance: AxiosInstance = Axios.create(defaultConfig)

  /** 重连原始请求 */
  private static retryOriginalRequest(config: KptHttpRequestConfig) {
    return new Promise((resolve) => {
      /* KptHttp.requests.push((token: string) => {
        config.headers['Authorization'] = formatToken(token)
        resolve(config)
      }) */
    })
  }

  /** 请求拦截 */
  private httpInterceptorsRequest(): void {
    KptHttp.axiosInstance.interceptors.request.use(
      async (config: KptHttpRequestConfig): Promise<any> => {
        // 开启进度条动画
        //  NProgress.start()
        // 优先判断post/get等方法是否传入回调，否则执行初始化设置等回调
        if (typeof config.beforeRequestCallback === 'function') {
          config.beforeRequestCallback(config)
          return config
        }
        if (KptHttp.initConfig.beforeRequestCallback) {
          KptHttp.initConfig.beforeRequestCallback(config)
          return config
        }
        /** 请求白名单，放置一些不需要token的接口（通过设置请求白名单，防止token过期后再请求造成的死循环问题） */
        const whiteList = ['/refresh-token', '/login']
        return whiteList.find((url) => url === config.url)
          ? config
          : new Promise((resolve) => {
              const data = getToken()
              if (data) {
                const now = new Date().getTime()
                const expired = data.expires - now <= 0
                if (expired) {
                  /* if (!KptHttp.isRefreshing) {
                    KptHttp.isRefreshing = true
                    // token过期刷新
                    useUserStoreHook()
                      .handRefreshToken({ refreshToken: data.refreshToken })
                      .then((res) => {
                        const token = res.data.accessToken
                        config.headers['Authorization'] = formatToken(token)
                        KptHttp.requests.forEach((cb) => cb(token))
                        KptHttp.requests = []
                      })
                      .finally(() => {
                        KptHttp.isRefreshing = false
                      })
                  } */
                  resolve(KptHttp.retryOriginalRequest(config))
                } else {
                  /*  config.headers['Authorization'] = formatToken(
                    data.accessToken
                  ) */
                  resolve(config)
                }
              } else {
                resolve(config)
              }
            })
      },
      (error) => {
        return Promise.reject(error)
      }
    )
  }

  /** 响应拦截 */
  private httpInterceptorsResponse(): void {
    const instance = KptHttp.axiosInstance
    instance.interceptors.response.use(
      (response: KptHttpResponse) => {
        const $config = response.config
        // 关闭进度条动画
        // NProgress.done()
        // 优先判断post/get等方法是否传入回调，否则执行初始化设置等回调
        if (typeof $config.beforeResponseCallback === 'function') {
          $config.beforeResponseCallback(response)
          return response.data
        }
        if (KptHttp.initConfig.beforeResponseCallback) {
          KptHttp.initConfig.beforeResponseCallback(response)
          return response.data
        }
        return response.data
      },
      (error: KptHttpError) => {
        const $error = error
        $error.isCancelRequest = Axios.isCancel($error)
        // 关闭进度条动画
        // NProgress.done()
        // 所有的响应异常 区分来源为取消请求/非取消请求
        return Promise.reject($error)
      }
    )
  }

  /** 通用请求工具函数 */
  public request<T>(
    method: RequestMethods,
    url: string,
    param?: AxiosRequestConfig,
    axiosConfig?: KptHttpRequestConfig
  ): Promise<T> {
    const config = {
      method,
      url,
      ...param,
      ...axiosConfig,
    } as KptHttpRequestConfig

    // 单独处理自定义请求/响应回调
    return new Promise((resolve, reject) => {
      KptHttp.axiosInstance
        .request(config)
        .then((response: any) => {
          resolve(response)
        })
        .catch((error) => {
          reject(error)
        })
    })
  }

  /** 单独抽离的post工具函数 */
  public post<T, P>(
    url: string,
    params?: AxiosRequestConfig<T>,
    config?: KptHttpRequestConfig
  ): Promise<P> {
    return this.request<P>('post', url, params, config)
  }

  /** 单独抽离的get工具函数 */
  public get<T, P>(
    url: string,
    params?: AxiosRequestConfig<T>,
    config?: KptHttpRequestConfig
  ): Promise<P> {
    return this.request<P>('get', url, params, config)
  }
}

export const http = new KptHttp()
